#include <QtCore/QSocketNotifier>
#include <QtNetwork/QHostInfo>
#include <QtEndian>

#include "../Common/bonjourrecord.h"
#include "bonjourserviceresolver.h"


void BonjourServiceResolver::cleanupResolve()
{
	if (dnssref)
	{
		DNSServiceRefDeallocate(dnssref);

		dnssref = 0;
		bonjourPort = -1;

		delete bonjourSocket;
	}
}

/** Resolve a server address and port from it's description given to the client. */
void BonjourServiceResolver::resolveBonjourRecord(const BonjourRecord &record)
{
	// We are already resolving.
	if (dnssref)
		return;

	DNSServiceErrorType err = DNSServiceResolve(&dnssref, 0, 0,
						    record.getServiceName().toUtf8().constData(),
						    record.getRegisteredType().toUtf8().constData(),
						    record.getReplyDomain().toUtf8().constData(),
						    (DNSServiceResolveReply)bonjourResolveReply,
						    this);

	if (err != kDNSServiceErr_NoError)
		emit error(err);

	else
	{
		int sockfd = DNSServiceRefSockFD(dnssref);

		if (sockfd == -1)
			emit error(kDNSServiceErr_Invalid);

		// Address resolved, notify that the info can be read from server now.
		else
		{
			bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read,
							    this);

			connect(bonjourSocket, SIGNAL(activated(int)), this,
				SLOT(bonjourSocketReadyRead()));
		}
	}
}

void BonjourServiceResolver::bonjourSocketReadyRead()
{
	DNSServiceErrorType err = DNSServiceProcessResult(dnssref);

	if (err != kDNSServiceErr_NoError)
		emit error(err);
}


void BonjourServiceResolver::bonjourResolveReply(DNSServiceRef, DNSServiceFlags,
						 quint32 , DNSServiceErrorType errorCode,
						 const char *, const char *hostTarget,
						 quint16 port, quint16 , const char *,
						 void *context)
{
	BonjourServiceResolver *serviceResolver = static_cast<BonjourServiceResolver *>(context);

	if (errorCode != kDNSServiceErr_NoError)
	{
		emit serviceResolver->error(errorCode);

		return;
	}

	// Convert port into big endian. Probably because apple used to be PPC. Stupid apple.
	port = qToLittleEndian(port);

	serviceResolver->bonjourPort = port;

	QHostInfo::lookupHost(hostTarget, serviceResolver,
			      SLOT(finishConnect(const QHostInfo &)));
}

void BonjourServiceResolver::finishConnect(const QHostInfo &hostInfo)
{
	emit bonjourRecordResolved(hostInfo, bonjourPort);

	QMetaObject::invokeMethod(this, "cleanupResolve", Qt::QueuedConnection);
}
